/*
 * Copyright 2008-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.faxsun.api.endpoint.cart;

import org.apache.commons.lang.StringUtils;
import org.broadleafcommerce.core.order.domain.Order;
import org.broadleafcommerce.core.order.domain.OrderItem;
import org.broadleafcommerce.core.order.service.OrderItemService;
import org.broadleafcommerce.core.order.service.call.OrderItemRequestDTO;
import org.broadleafcommerce.core.order.service.exception.AddToCartException;
import org.broadleafcommerce.core.order.service.exception.RemoveFromCartException;
import org.broadleafcommerce.core.order.service.type.OrderStatus;
import org.broadleafcommerce.core.pricing.service.exception.PricingException;
import org.broadleafcommerce.core.web.api.BroadleafWebServicesException;
import org.broadleafcommerce.core.web.api.wrapper.OrderWrapper;
import org.broadleafcommerce.profile.core.domain.Customer;
import org.broadleafcommerce.profile.web.core.CustomerState;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import com.faxsun.api.wrapper.order.OrderItemWrapper;
import com.faxsun.controller.account.ManageWishlistController;
import com.faxsun.core.order.domain.FSOrderImpl;
import com.faxsun.core.order.service.FSOrderItemServiceImpl;
import com.faxsun.core.order.service.FSOrderService;
import com.faxsun.core.order.service.type.FSInternalOrderStatus;
import com.faxsun.core.order.service.type.FSOrderStatus;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;

/**
 * This is a reference REST API endpoint for order history. This can be
 * modified, used as is, or removed. The purpose is to provide an out of the box
 * RESTful order history service implementation, but also to allow the
 * implementor to have fine control over the actual API, URIs, and general
 * JAX-RS annotations.
 * 
 * @author Kelly Tisdell
 *
 */
@Component
@Scope("singleton")
@Path("/orders/")
@Produces(value = { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Consumes(value = { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public class OrderHistoryEndpoint extends
		org.broadleafcommerce.core.web.api.endpoint.order.OrderHistoryEndpoint {
	public static final String CART_IS_NULL = "org.broadleafcommerce.core.web.api.BroadleafWebServicesException.CartIsNull";
	public static final String CUSTOMER_OR_STATUS_ERROR = "org.broadleafcommerce.core.web.api.BroadleafWebServicesException.CustomerOrStatusIsError";
	public static final String NO_REFUND_ITEMS = "org.broadleafcommerce.core.web.api.BroadleafWebServicesException.NoRefundOrderItems";
	
	
	@Resource(name = "blOrderService")
	protected FSOrderService blOrderService;
	
	@Resource(name = "blOrderItemService")
	protected OrderItemService orderItemService;
	
	/*
	 * Status supported: 
	 * UNPAID --- PREDELIVERY --- DELIVERY(待收货) --- SIGNED(待评价)
	 */	
	@Override
	@GET
	public List<OrderWrapper> findOrdersForCustomer(
			@Context HttpServletRequest request,
			@QueryParam("orderStatus") @DefaultValue("SUBMITTED") String orderStatus) {
		Customer customer = CustomerState.getCustomer(request);
		OrderStatus status = null;
		if (orderStatus.equals("UNPAID")  ) {
			status = FSOrderStatus.getInstance("SUBMITTED");
		}
		else if(orderStatus.equals("PREDELIVERY")){
			status = FSOrderStatus.getInstance("CONFIRMED");
		}
		else{
			status = FSOrderStatus.getInstance(orderStatus);
		}

		if (customer != null && status != null) {
			List<Order> orders = blOrderService.findOrdersForCustomer(customer,status);
			String internalstatus = null;
			// unpaid = submitted + [PAYMENT_SUBMITTED | PAYMENT_FAIL | PAYMENT_IN_PROCESS]
			if (orderStatus.equals("UNPAID")) {
				Iterator<Order> iter = orders.iterator();
				while (iter.hasNext()) {
					FSInternalOrderStatus internalStatus = ((FSOrderImpl) iter
							.next()).getInternalStatus();
					if (internalStatus != null) {
						internalstatus = internalStatus.getType();
						if (internalstatus.isEmpty()
								|| !(internalstatus.equals("PAYMENT_SUBMITTED") 
										|| internalstatus.equals("PAYMENT_FAIL")
										|| internalstatus.equals("PAYMENT_IN_PROCESS"))) {
							iter.remove();
						}
					}else {
						iter.remove();
					}
				}
			}
			// PREDELIVERY = CONFIRMED +paid { submitted + [PAYMENT_SUCCESS | PAYMENT_PROCESS_FAIL] }
			else if (orderStatus.equals("PREDELIVERY")) {				
				Iterator<Order> iter = orders.iterator();
				while (iter.hasNext()) {
					FSInternalOrderStatus internalStatus = ((FSOrderImpl) iter
							.next()).getInternalStatus();
					if (internalStatus != null) {
						internalstatus = internalStatus.getType();
						if (internalstatus.isEmpty()
								|| !(internalstatus.equals("PAYMENT_SUCCESS") 
										|| internalstatus.equals("PAYMENT_PROCESS_FAIL"))) {
							iter.remove();
						}
					}else{
						iter.remove();
					}
				}
			}

			if (orders != null && !orders.isEmpty()) {
				List<OrderWrapper> wrappers = new ArrayList<OrderWrapper>();
				for (Order order : orders) {
					OrderWrapper wrapper = (OrderWrapper) context
							.getBean(OrderWrapper.class.getName());
					wrapper.wrapSummary(order, request);
					wrappers.add(wrapper);
				}
				return wrappers;
			}

			throw BroadleafWebServicesException.build(
					Response.Status.NOT_FOUND.getStatusCode()).addMessage(
					CART_IS_NULL);
		}

		throw BroadleafWebServicesException.build(
				Response.Status.BAD_REQUEST.getStatusCode()).addMessage(CUSTOMER_OR_STATUS_ERROR);
	}

	@GET
	@Path("all")
	public List<OrderWrapper> findOrdersForCustomer(
			@Context HttpServletRequest request) {
		Customer customer = CustomerState.getCustomer(request);

		if (customer != null) {
			List<Order> orders = blOrderService.findOrdersForCustomer(customer);
			String orderStatus = null;
			Iterator<Order> iter = orders.iterator();
			FSOrderImpl orderImpl = null;
			// remove items which are not in these status
			while (iter.hasNext()) {
				orderImpl = ((FSOrderImpl) iter.next());
				orderStatus = orderImpl.getStatus().getType();				
				if (!(orderStatus.equals("CONFIRMED")
						|| orderStatus.equals("DELIVERY")
						|| orderStatus.equals("SIGNED") 
						|| orderStatus.equals("CANCELLED")
						|| orderStatus.equals("SUBMITTED"))) {
					iter.remove();	
				}
				else if (orderStatus.equals("SUBMITTED")) {  // paid
					FSInternalOrderStatus internalStatus = orderImpl.getInternalStatus();
					if (internalStatus != null) {
						String internalstatus = internalStatus.getType();
						if (internalstatus.isEmpty()
								|| !(internalstatus
										.equals("PAYMENT_SUCCESS") || internalstatus
										.equals("PAYMENT_PROCESS_FAIL") )) {
							iter.remove();
						}
					}else{
						iter.remove();
					}
				}
			}

			if (orders != null && !orders.isEmpty()) {
				List<OrderWrapper> wrappers = new ArrayList<OrderWrapper>();

				for (Order order : orders) {
					OrderWrapper wrapper = (OrderWrapper) context
							.getBean(OrderWrapper.class.getName());
					wrapper.wrapSummary(order, request);
					wrappers.add(wrapper);
				}
				return wrappers;
			}

			throw BroadleafWebServicesException.build(
					Response.Status.NOT_FOUND.getStatusCode()).addMessage(
					BroadleafWebServicesException.CART_NOT_FOUND);
		}

		throw BroadleafWebServicesException.build(
				Response.Status.BAD_REQUEST.getStatusCode()).addMessage(CUSTOMER_OR_STATUS_ERROR);
	}
	
	/*
	 * Refund:  Now in internal order status.   orderItems
	 * internalorderStatus.equals("REFUND_REQUEST") || internalorderStatus.equals("REFUND_PROCESSING")|| internalorderStatus.equals("REFUND_COMPLETE")	
	 */
	@GET
	@Path("refund")
	public List<OrderItemWrapper> findRefundOrdersForCustomer(
			@Context HttpServletRequest request) {
		Customer customer = CustomerState.getCustomer(request);
		FSOrderItemServiceImpl fsOrderItemService = (FSOrderItemServiceImpl) orderItemService;
		List<OrderItem> orderitems = fsOrderItemService.readReFoundOrderItemsByCustomer(customer);

		if(orderitems != null){
			List<OrderItemWrapper> wrappers = new ArrayList<OrderItemWrapper>();
			for (OrderItem orderItem : orderitems) {
				OrderItemWrapper wrapper = (OrderItemWrapper) context.getBean("fsOrderItemWrapper");
				wrapper.wrapSummary(orderItem, request);
				wrappers.add(wrapper);
			}
			return wrappers;
		}
		
		throw BroadleafWebServicesException.build(
				Response.Status.NOT_FOUND.getStatusCode()).addMessage(NO_REFUND_ITEMS);
	}
	
	// orderStatus = NAMED(收藏) 
	@GET
	@Path("wishlist")
	public List<OrderItemWrapper> findWishListForCustomer(@Context HttpServletRequest request){
		Order wishlist = orderService.findNamedOrderForCustomer(ManageWishlistController.WISHLIST_ORDER_NAME, CustomerState.getCustomer());
		List<OrderItem> orderitems = wishlist.getOrderItems();
		if(orderitems != null){
			List<OrderItemWrapper> wrappers = new ArrayList<OrderItemWrapper>();
			for (OrderItem orderItem : orderitems) {
				OrderItemWrapper wrapper = (OrderItemWrapper) context.getBean("fsOrderItemWrapper");
				wrapper.wrapSummary(orderItem, request);
				wrappers.add(wrapper);
			}
			return wrappers;
		}
		
		throw BroadleafWebServicesException.build(
				Response.Status.NOT_FOUND.getStatusCode()).addMessage(NO_REFUND_ITEMS);
	}
	
	
	/**
	 * 添加商品到收藏夹
	 * @param request
	 * @param uriInfo
	 * @param productId
	 * @param categoryId
	 * @param quantity
	 * @param priceOrder
	 * @return
	 */
	//
	@POST
	@Path("wishlist/add/{productId}")
	@Consumes("application/x-www-form-urlencoded")
	public List<OrderItemWrapper> addProductToWishlist(@Context HttpServletRequest request,@Context UriInfo uriInfo,
			@PathParam("productId") Long productId,
			@FormParam("categoryId") Long categoryId,
			@FormParam("quantity") @DefaultValue("1") int quantity,
			@FormParam("priceOrder") @DefaultValue("true") boolean priceOrder){
		Customer customer = CustomerState.getCustomer();
		Order wishlist = orderService.findNamedOrderForCustomer(ManageWishlistController.WISHLIST_ORDER_NAME, customer);
		if (wishlist == null) {
            wishlist = orderService.createNamedOrderForCustomer(ManageWishlistController.WISHLIST_ORDER_NAME, customer);
        }
		
		try {
            //We allow product options to be submitted via form post or via query params.  We need to take 
            //the product options and build a map with them...
            HashMap<String, String> productOptions = getOptions(uriInfo);

            OrderItemRequestDTO orderItemRequestDTO = new OrderItemRequestDTO();
            orderItemRequestDTO.setProductId(productId);
            orderItemRequestDTO.setCategoryId(categoryId);
            orderItemRequestDTO.setQuantity(quantity);

            //If we have product options set them on the DTO
            if (productOptions.size() > 0) {
                orderItemRequestDTO.setItemAttributes(productOptions);
            }

            wishlist = orderService.addItem(wishlist.getId(), orderItemRequestDTO, priceOrder);
            wishlist = orderService.save(wishlist, priceOrder);

            OrderWrapper wrapper = (OrderWrapper) context.getBean(OrderWrapper.class.getName());
            wrapper.wrapDetails(wishlist, request);
            List<OrderItem> orderitems = wishlist.getOrderItems();
    		if(orderitems != null){
    			List<OrderItemWrapper> wrappers = new ArrayList<OrderItemWrapper>();
    			for (OrderItem orderItem : orderitems) {
    				OrderItemWrapper wrappered = (OrderItemWrapper) context.getBean("fsOrderItemWrapper");
    				wrappered.wrapSummary(orderItem, request);
    				wrappers.add(wrappered);
    			}
    			return wrappers;
    		 } 
		}catch (PricingException e) {
            throw BroadleafWebServicesException.build(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), null, null, e);
        } catch (AddToCartException e) {
            throw BroadleafWebServicesException.build(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), null, null, e);
        }
       
		throw BroadleafWebServicesException.build(
				Response.Status.NOT_FOUND.getStatusCode()).addMessage(NO_REFUND_ITEMS);
	}
	
	protected HashMap<String, String> getOptions(UriInfo uriInfo) {
        MultivaluedMap<String, String> multiValuedMap = uriInfo.getQueryParameters();
        HashMap<String, String> productOptions = new HashMap<String, String>();

        //Fill up a map of key values that will represent product options
        Set<String> keySet = multiValuedMap.keySet();
        for (String key : keySet) {
            if (multiValuedMap.getFirst(key) != null) {
                //Product options should be returned with "productOption." as a prefix. We'll look for those, and 
                //remove the prefix.
                if (key.startsWith("productOption.")) {
                    productOptions.put(StringUtils.removeStart(key, "productOption."), multiValuedMap.getFirst(key));
                }
            }
        }
        return productOptions;
    }
	
	
	/**
	 * 从收藏夹加到购物车
	 * @param request
	 * @return
	 */
	@POST
	@Path("wishlist/addFromWishlist")
	@Consumes("application/x-www-form-urlencoded")
	public List<OrderItemWrapper> addFromWishlist(@Context HttpServletRequest request,
			@FormParam("id") Long orderItemId){
		
		Order wishlist = orderService.findNamedOrderForCustomer(ManageWishlistController.WISHLIST_ORDER_NAME, CustomerState.getCustomer());
        List<OrderItem> orderItems = wishlist.getOrderItems();

        OrderItem orderItem = null;
        for (OrderItem item : orderItems) {
            if (orderItemId.equals(item.getId())) {
                orderItem = item;
                break;
            }
        }

        if (orderItem != null) {
            try {
				orderService.addItemFromNamedOrder(wishlist, orderItem, true);
			} catch (RemoveFromCartException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (AddToCartException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
        } else {
            throw new IllegalArgumentException("The item id provided was not found in the wishlist");
        }

		{
			List<OrderItemWrapper> wrappers = new ArrayList<OrderItemWrapper>();
			for (OrderItem orderItemed : orderItems) {
				OrderItemWrapper wrapper = (OrderItemWrapper) context.getBean("fsOrderItemWrapper");
				wrapper.wrapSummary(orderItemed, request);
				wrappers.add(wrapper);
			}
			return wrappers;
		}
	}
	
	@POST
	@Path("wishlist/delete")
	@Consumes("application/x-www-form-urlencoded")
	public List<OrderItemWrapper> deleteWishListItem(@Context HttpServletRequest request,
			@FormParam("id") Long orderItemId){
		Order wishlist = orderService.findNamedOrderForCustomer(ManageWishlistController.WISHLIST_ORDER_NAME, CustomerState.getCustomer());
        List<OrderItem> orderItems = wishlist.getOrderItems();

        try {
        	orderService.removeItem(wishlist.getId(), orderItemId, false);
		} catch (RemoveFromCartException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 

		List<OrderItemWrapper> wrappers = new ArrayList<OrderItemWrapper>();
		for (OrderItem orderItemed : orderItems) {
			OrderItemWrapper wrapper = (OrderItemWrapper) context.getBean("fsOrderItemWrapper");
			wrapper.wrapSummary(orderItemed, request);
			wrappers.add(wrapper);
		}
		return wrappers;
	}
}
